﻿package  
{
	import org.flashdevelop.utils.FlashConnect; // FlashConnect.trace( "Adding tile" );
	
	// Working class for the actual solving of the puzzle.
	//
	public class Solver 
	{
		// Constructor
		//
		public function Solver() 
		{
			
		}
		
		public function SolveViaRow( rowNumber:Number, cellNumber:Number, boardState:Array, boardSize:Number ) : void
		{
			// Get the row in question
			var row:Array = boardState[ rowNumber ];
			
			// Get the tile in question
			var tile:Tile = row[ cellNumber ];
			
			// Loop through all the states in the tile.
			for ( var indexNum:Number = 0; indexNum < tile.GetNumStates( ); indexNum++ )
			{
				// Get the status of this number
				var status:Number = tile.GetValueState( indexNum );
				
				// Is this state a possible for this tile?
				if ( status == Tile.VALUE_STATE_POSSIBLE || status == Tile.VALUE_STATE_UNKNOWN )
				{
					// Keep track of how many marked this number as not possible for them.  If 
					// all of them do that, than we know that it is a confirmed for us!
					var numNotPossible:Number = 0;
					
					// Now loop through each cell in the row.
					for ( var cell:Number = 0; cell < boardSize; cell++ )
					{
						// We don't want to check against ourselves.
						if ( cell == cellNumber )
						{
							continue;
						}
						
						// If someone has marked this number as confirmed, than it is a Not Possible for
						// us!
						if ( row[cell].GetValueState( indexNum ) == Tile.VALUE_STATE_CONFIRMED )
						{
							tile.SetValueState( indexNum, Tile.VALUE_STATE_NOT_POSSIBLE );
							
							// Done with this number
							break;
						}
						else if ( row[cell].GetValueState( indexNum ) == Tile.VALUE_STATE_NOT_POSSIBLE )
						{
							numNotPossible++;
						}
					}
					
					// Has everyone but us marked this number as not possible?
					if ( numNotPossible == boardSize - 1 )
					{
						// If so we can mark this number as confirmed for us!
						tile.SetValueState( indexNum, Tile.VALUE_STATE_CONFIRMED );
						
						// The tile is solved, so lets move on!
						return;
					}
				}
			}
		}
		
		public function SolveViaCol( rowNumber:Number, cellNumber:Number, boardState:Array, boardSize:Number ) : void
		{
			// Get the tile in question
			var tile:Tile = boardState[ rowNumber ][ cellNumber ];
			
			// Loop through all the states in the tile.
			for ( var indexNum:Number = 0; indexNum < tile.GetNumStates( ); indexNum++ )
			{
				// Get the status of this number
				var status:Number = tile.GetValueState( indexNum );
				
				// Is this state a possible for this tile?
				if ( status == Tile.VALUE_STATE_POSSIBLE )
				{
					// Keep track of how many marked this number as not possible for them.  If 
					// all of them do that, than we know that it is a confirmed for us!
					var numNotPossible:Number = 0;
					
					// Now loop through each cell in the row.
					for ( var row:Number = 0; row < boardSize; row++ )
					{
						// We don't want to check against ourselves.
						if ( row == rowNumber )
						{
							continue;
						}
						
						// If someone has marked this number as confirmed, than it is a Not Possible for
						// us!
						if ( boardState[ row ][ cellNumber ].GetValueState( indexNum ) == Tile.VALUE_STATE_CONFIRMED )
						{
							tile.SetValueState( indexNum, Tile.VALUE_STATE_NOT_POSSIBLE );
							
							// Done with this number
							break;
						}
						else if ( boardState[ row ][ cellNumber ].GetValueState( indexNum ) == Tile.VALUE_STATE_NOT_POSSIBLE )
						{
							numNotPossible++;
						}
					}
					
					// Has everyone but us marked this number as not possible?
					if ( numNotPossible == boardSize - 1 )
					{
						// If so we can mark this number as confirmed for us!
						tile.SetValueState( indexNum, Tile.VALUE_STATE_CONFIRMED );
						
						// The tile is solved, so lets move on!
						return;
					}
				}
			}
		}
		
		public function SolveViaBlock( rowNumber:Number, cellNumber:Number, boardState:Array, boardSize:Number ) : void
		{
			// Get the tile in question
			var tile:Tile = boardState[ rowNumber ][ cellNumber ];

			// This assumes that there are always 3 blocks per row/col.  I'm not sure if that's true
			// for large Sudoku puzzles...
			var blockSize:Number = ( boardSize / 3 );
			
			// Figure out which blocks we fall into
			var rowBlock:Number = Math.floor( rowNumber / blockSize );
			var cellBlock:Number = Math.floor( cellNumber / blockSize );
			
			// Figure out the index in the board state that this block starts
			var startRow:Number = rowBlock * blockSize;
			var startCell:Number = cellBlock * blockSize;
			
			var endRow:Number = startRow + blockSize;
			var endCell:Number = startCell + blockSize;
			
			// Loop through all the states in the tile.
			for ( var indexNum:Number = 0; indexNum < tile.GetNumStates( ); indexNum++ )
			{
    			// Get the status of this number
				var status:Number = tile.GetValueState( indexNum );
				
				// Is this state a possible for this tile?
				if ( status == Tile.VALUE_STATE_POSSIBLE )
				{
					// Keep track of how many marked this number as not possible for them.  If 
					// all of them do that, than we know that it is a confirmed for us!
					var numNotPossible:Number = 0;
					
					for ( var row:Number = startRow; row < endRow; row++ )
					{
						for ( var cell:Number = startCell; cell < endCell; cell++ )
						{
							// Make sure this isn't the cell we are supposed to be comparing against
							if ( rowNumber == row && cellNumber == cell )
							{
								continue;
							}
							
							// If someone has marked this number as confirmed, than it is a Not Possible for
							// us!
							if ( boardState[ row ][ cell ].GetValueState( indexNum ) == Tile.VALUE_STATE_CONFIRMED )
							{
								tile.SetValueState( indexNum, Tile.VALUE_STATE_NOT_POSSIBLE );
								
								// Done with this number
								break;
							}
							else if ( boardState[ row ][ cell ].GetValueState( indexNum ) == Tile.VALUE_STATE_NOT_POSSIBLE )
							{
								numNotPossible++;
							}
						}
					}
						
					// Has everyone but us marked this number as not possible?
					if ( numNotPossible == ( blockSize * blockSize ) - 1 )
					{
						// If so we can mark this number as confirmed for us!
						tile.SetValueState( indexNum, Tile.VALUE_STATE_CONFIRMED );
						
						// The tile is solved, so lets move on!
						return;
					}
				}
			}
		}
		
		public function SolveViaSelf( rowNumber:Number, cellNumber:Number, boardState:Array ) : void
		{
			// Keep track of the number which has been set to possible.  If we only have 1,
			// than it is confirmed.
			var possible:Number = -1;
			
			// Get the tile in question
			var tile:Tile = boardState[ rowNumber ][ cellNumber ];
			
			// Loop through all the states in the tile.
			for ( var indexNum:Number = 0; indexNum < tile.GetNumStates( ); indexNum++ )
			{
				// Get the status of this number
				var status:Number = tile.GetValueState( indexNum );
				
				if ( status == Tile.VALUE_STATE_POSSIBLE )
				{
					// If we already found a possible number than this check is
					// not going to work.  Time to leave.
					if ( possible != -1 )
					{
						return;
					}
					else
					{
						possible = indexNum;
					}
				}
			}
			
			// If we made it to this point and have a possible, that means it was the only one,
			// and thus MUST be the number for this cell!
			if ( possible != -1 )
			{
				tile.SetValueState( possible, Tile.VALUE_STATE_CONFIRMED );
			}
		}
	}
	
}